#include "hidbox/mouse_descriptor_builder.h"

namespace hidbox {

// HID 报告描述符常量
constexpr u8 USAGE_PAGE_GENERIC_DESKTOP = 0x01;
constexpr u8 USAGE_PAGE_BUTTON = 0x09;
constexpr u8 USAGE_MOUSE = 0x02;
constexpr u8 USAGE_POINTER = 0x01;
constexpr u8 USAGE_BUTTON = 0x01;
constexpr u8 USAGE_X = 0x30;
constexpr u8 USAGE_Y = 0x31;
constexpr u8 USAGE_WHEEL = 0x38;

std::vector<u8> MouseDescriptorBuilder::BuildStandardMouse() {
    return std::vector<u8>{
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  // Usage Page (Generic Desktop)
            0x09, USAGE_MOUSE,                  // Usage (Mouse)
            0xA1, 0x01,                         // Collection (Application)
            0x09, USAGE_POINTER,                //   Usage (Pointer)
            0xA1, 0x00,                         //   Collection (Physical)
            0x05, USAGE_PAGE_BUTTON,            //     Usage Page (Button)
            0x19, 0x01,                         //     Usage Minimum (Button 1)
            0x29, 0x03,                         //     Usage Maximum (Button 3)
            0x15, 0x00,                         //     Logical Minimum (0)
            0x25, 0x01,                         //     Logical Maximum (1)
            0x95, 0x03,                         //     Report Count (3)
            0x75, 0x01,                         //     Report Size (1)
            0x81, 0x02,                         //     Input (Data, Variable, Absolute)
            0x95, 0x01,                         //     Report Count (1)
            0x75, 0x05,                         //     Report Size (5)
            0x81, 0x01,                         //     Input (Constant) - Padding
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  //     Usage Page (Generic Desktop)
            0x09, USAGE_X,                      //     Usage (X)
            0x09, USAGE_Y,                      //     Usage (Y)
            0x15, 0x81,                         //     Logical Minimum (-127)
            0x25, 0x7F,                         //     Logical Maximum (127)
            0x75, 0x08,                         //     Report Size (8)
            0x95, 0x02,                         //     Report Count (2)
            0x81, 0x06,                         //     Input (Data, Variable, Relative)
            0xC0,                               //   End Collection
            0xC0                                // End Collection
    };
}

std::vector<u8> MouseDescriptorBuilder::BuildMouseWithWheel() {
    return std::vector<u8>{
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  // Usage Page (Generic Desktop)
            0x09, USAGE_MOUSE,                  // Usage (Mouse)
            0xA1, 0x01,                         // Collection (Application)
            0x09, USAGE_POINTER,                //   Usage (Pointer)
            0xA1, 0x00,                         //   Collection (Physical)
            0x05, USAGE_PAGE_BUTTON,            //     Usage Page (Button)
            0x19, 0x01,                         //     Usage Minimum (Button 1)
            0x29, 0x05,                         //     Usage Maximum (Button 5)
            0x15, 0x00,                         //     Logical Minimum (0)
            0x25, 0x01,                         //     Logical Maximum (1)
            0x95, 0x05,                         //     Report Count (5)
            0x75, 0x01,                         //     Report Size (1)
            0x81, 0x02,                         //     Input (Data, Variable, Absolute)
            0x95, 0x01,                         //     Report Count (1)
            0x75, 0x03,                         //     Report Size (3)
            0x81, 0x01,                         //     Input (Constant) - Padding
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  //     Usage Page (Generic Desktop)
            0x09, USAGE_X,                      //     Usage (X)
            0x09, USAGE_Y,                      //     Usage (Y)
            0x15, 0x81,                         //     Logical Minimum (-127)
            0x25, 0x7F,                         //     Logical Maximum (127)
            0x75, 0x08,                         //     Report Size (8)
            0x95, 0x02,                         //     Report Count (2)
            0x81, 0x06,                         //     Input (Data, Variable, Relative)
            0x09, USAGE_WHEEL,                  //     Usage (Wheel)
            0x15, 0x81,                         //     Logical Minimum (-127)
            0x25, 0x7F,                         //     Logical Maximum (127)
            0x75, 0x08,                         //     Report Size (8)
            0x95, 0x01,                         //     Report Count (1)
            0x81, 0x06,                         //     Input (Data, Variable, Relative)
            0xC0,                               //   End Collection
            0xC0                                // End Collection
    };
}

std::vector<u8> MouseDescriptorBuilder::BuildGamingMouse() {
    return std::vector<u8>{
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  // Usage Page (Generic Desktop)
            0x09, USAGE_MOUSE,                  // Usage (Mouse)
            0xA1, 0x01,                         // Collection (Application)
            0x09, USAGE_POINTER,                //   Usage (Pointer)
            0xA1, 0x00,                         //   Collection (Physical)
            0x05, USAGE_PAGE_BUTTON,            //     Usage Page (Button)
            0x19, 0x01,                         //     Usage Minimum (Button 1)
            0x29, 0x08,                         //     Usage Maximum (Button 8)
            0x15, 0x00,                         //     Logical Minimum (0)
            0x25, 0x01,                         //     Logical Maximum (1)
            0x95, 0x08,                         //     Report Count (8)
            0x75, 0x01,                         //     Report Size (1)
            0x81, 0x02,                         //     Input (Data, Variable, Absolute)
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  //     Usage Page (Generic Desktop)
            0x09, USAGE_X,                      //     Usage (X)
            0x09, USAGE_Y,                      //     Usage (Y)
            0x16, 0x01, 0x80,                   //     Logical Minimum (-32767)
            0x26, 0xFF, 0x7F,                   //     Logical Maximum (32767)
            0x75, 0x10,                         //     Report Size (16)
            0x95, 0x02,                         //     Report Count (2)
            0x81, 0x06,                         //     Input (Data, Variable, Relative)
            0x09, USAGE_WHEEL,                  //     Usage (Wheel)
            0x15, 0x81,                         //     Logical Minimum (-127)
            0x25, 0x7F,                         //     Logical Maximum (127)
            0x75, 0x08,                         //     Report Size (8)
            0x95, 0x01,                         //     Report Count (1)
            0x81, 0x06,                         //     Input (Data, Variable, Relative)
            0xC0,                               //   End Collection
            0xC0                                // End Collection
    };
}

std::vector<u8> MouseDescriptorBuilder::BuildCustomMouse(u8 num_buttons,
                                                         bool has_wheel,
                                                         bool high_precision) {
    if (num_buttons < 1) num_buttons = 1;
    if (num_buttons > 16) num_buttons = 16;

    std::vector<u8> descriptor{
            0x05, USAGE_PAGE_GENERIC_DESKTOP,  // Usage Page (Generic Desktop)
            0x09, USAGE_MOUSE,                  // Usage (Mouse)
            0xA1, 0x01,                         // Collection (Application)
            0x09, USAGE_POINTER,                //   Usage (Pointer)
            0xA1, 0x00,                         //   Collection (Physical)
            0x05, USAGE_PAGE_BUTTON,            //     Usage Page (Button)
            0x19, 0x01,                         //     Usage Minimum (Button 1)
            0x29, num_buttons,                  //     Usage Maximum (Button N)
            0x15, 0x00,                         //     Logical Minimum (0)
            0x25, 0x01,                         //     Logical Maximum (1)
            0x95, num_buttons,                  //     Report Count (N)
            0x75, 0x01,                         //     Report Size (1)
            0x81, 0x02,                         //     Input (Data, Variable, Absolute)
    };

    // 添加填充位
    u8 padding_bits = 8 - (num_buttons % 8);
    if (padding_bits < 8) {
        descriptor.push_back(0x95);
        descriptor.push_back(0x01);  // Report Count (1)
        descriptor.push_back(0x75);
        descriptor.push_back(padding_bits);  // Report Size (padding)
        descriptor.push_back(0x81);
        descriptor.push_back(0x01);  // Input (Constant)
    }

    // 添加 X/Y 坐标
    descriptor.push_back(0x05);
    descriptor.push_back(USAGE_PAGE_GENERIC_DESKTOP);
    descriptor.push_back(0x09);
    descriptor.push_back(USAGE_X);
    descriptor.push_back(0x09);
    descriptor.push_back(USAGE_Y);

    if (high_precision) {
        // 16位高精度
        descriptor.push_back(0x16);
        descriptor.push_back(0x01);
        descriptor.push_back(0x80);  // Logical Minimum (-32767)
        descriptor.push_back(0x26);
        descriptor.push_back(0xFF);
        descriptor.push_back(0x7F);  // Logical Maximum (32767)
        descriptor.push_back(0x75);
        descriptor.push_back(0x10);  // Report Size (16)
    } else {
        // 8位标准精度
        descriptor.push_back(0x15);
        descriptor.push_back(0x81);  // Logical Minimum (-127)
        descriptor.push_back(0x25);
        descriptor.push_back(0x7F);  // Logical Maximum (127)
        descriptor.push_back(0x75);
        descriptor.push_back(0x08);  // Report Size (8)
    }

    descriptor.push_back(0x95);
    descriptor.push_back(0x02);  // Report Count (2)
    descriptor.push_back(0x81);
    descriptor.push_back(0x06);  // Input (Data, Variable, Relative)

    // 添加滚轮（如果需要）
    if (has_wheel) {
        descriptor.push_back(0x09);
        descriptor.push_back(USAGE_WHEEL);
        descriptor.push_back(0x15);
        descriptor.push_back(0x81);  // Logical Minimum (-127)
        descriptor.push_back(0x25);
        descriptor.push_back(0x7F);  // Logical Maximum (127)
        descriptor.push_back(0x75);
        descriptor.push_back(0x08);  // Report Size (8)
        descriptor.push_back(0x95);
        descriptor.push_back(0x01);  // Report Count (1)
        descriptor.push_back(0x81);
        descriptor.push_back(0x06);  // Input (Data, Variable, Relative)
    }

    descriptor.push_back(0xC0);  // End Collection
    descriptor.push_back(0xC0);  // End Collection

    return descriptor;
}

}  // namespace hidbox
